package com.ht.api.db.remote;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.springframework.stereotype.Component;

import com.ht.api.db.Entity;
import com.ht.api.db.bean.AjaxResult;
import com.ht.api.db.util.RedisUtil;

import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 第三方接口调用配置
 * @author asq
 * @createTime 2024年12月16日 10:49:33
 */
@Component
@Slf4j
public class ApiConfig {
	/** 所有的三方接口频率限制规则 */
	public static final Map<String, List<RateLimit>> rateMap = new HashMap<>();
	
	/** 暂停访问的url */
	private static final Set<String> closeList = new HashSet<>();
	
	/**
	 * 标记一个接口可访问
	 * @param apiId 接口ID
	 */
	public static void enableUrl(long apiId) {
		closeList.remove(getApiUrl(apiId));
	}
	
	/**
	 * 标记一个接口不可访问
	 * @param apiId 接口ID
	 */
	public static void disableUrl(long apiId) {
		closeList.add(getApiUrl(apiId));
	}
	
	/**
	 * 获取接口的url
	 * @param apiId
	 * @return
	 */
	private static String getApiUrl(long apiId) {
		Entity api = RedisUtil.get("open_api" + apiId);
		JSONObject apiConfig = api.getJSONObject("config");
		return apiConfig.getStr("url");
	}
	
	/**
	 * 检查一个url的访问频率
	 * @param url
	 * @return
	 */
	public AjaxResult checkRateLimit(String url) {
		if (closeList.contains(url)) {
			return AjaxResult.error("因访问频率受限，已自动关闭此接口");
		}
		
		// 1.获取基本url
		String baseUrl = getBaseUrl(url);
		
		// 2.在本地找到该url对应的频率规则列表
		List<RateLimit> rateList = rateMap.get(baseUrl);
		
		// 3.同步redis，使本地的规则以缓存中的数据为准
		sysCache(rateList);
		
		// 4.逐个验证频率是否超标
		return check(rateList);
	}

	/**
	 * 更新缓存
	 * @param r
	 */
	public void updateCache(RateLimit r) {
		Long ttl = RedisUtil.getExpire(r.getCacheKey());
		long expire = ttl > 0 ? ttl : r.getTime();
		RedisUtil.set(r.getCacheKey(), JSONUtil.toJsonStr(r), expire, TimeUnit.SECONDS);
	}
	
	/**
	 * 同步redis中的数据到本地
	 * @param rateList 本地的访问频率限制规则
	 */
	private void sysCache(List<RateLimit> rateList) {
		if (rateList == null) {
			return;
		}
		rateList.stream().forEach(r -> {
			String rateJson = RedisUtil.get(r.getCacheKey());
			if (rateJson != null) {
				RateLimit cacheRate = JSONUtil.toBean(rateJson, RateLimit.class);
				r.setCur(cacheRate.getCur());
			} else {
				r.setCur(0);
			}
		});
	}

	/**
	 * 检查所有的频率限制规则
	 * @param rateList 频率限制规则列表
	 * @return
	 */
	private AjaxResult check(List<RateLimit> rateList) {
		if (rateList != null) {
			RateLimit fullRate = rateList.stream().filter(r -> r.isFull()).findFirst().orElse(null);
			if (fullRate != null) {
				return AjaxResult.error(fullRate.getName());
			} else {
				// 通过频率检查后，所有频率次数+1，并更新缓存
				rateList.stream().forEach(r -> {
					r.setCur(r.getCur() + 1);
					
					// 更新缓存中的访问次数
					updateCache(r);
				});
				
				return AjaxResult.success();
			}
		}
		return AjaxResult.success();
	}

	/**
	 * 获取不带参数的url
	 * @param url
	 * @return
	 */
	private String getBaseUrl(String url) {
	    if (url == null || url.isEmpty()) {
	        return url;
	    }
	    int index = url.indexOf("?");
	    return index > 0 ? url.substring(0, index) : url;
	}
}
